<template>
  <!-- 本体部分 -->
  <div
    :id="id"
    :class="['vue-puzzle-vcode', { show_: show }]"
    @mousedown="onCloseMouseDown"
    @mouseup="onCloseMouseUp"
    @touchstart="onCloseMouseDown"
    @touchend="onCloseMouseUp"
  >
    <div
      v-show="isSlider"
      class="vue-auth-box_"
      :style="{ 'border-radius': borderRadius + 'px' }"
      @mousedown.stop
      @touchstart.stop
    >
      <div class="auth-body_" :style="`height: ${canvasHeight}px`">
        <!-- 主图，有缺口 -->
        <img ref="img1" :src="image1" alt="" :width="canvasWidth" :height="canvasHeight" />
        <!-- 小图 -->
        <img
          ref="img2"
          :src="image2"
          class="auth-canvas2_"
          :height="canvasHeight"
          :style="`transform:translateX(${styleWidth - sliderBaseSize}px)`"
          alt=""
        />
        <div :class="['loading-box_', { hide_: !loading }]">
          <div class="loading-gif_">
            <span />
            <span />
            <span />
            <span />
            <span />
          </div>
        </div>
        <div :class="['info-box_', { show: infoBoxShow }, { fail: infoBoxFail }]">
          {{ infoText }}
        </div>
        <div
          :class="['flash_', { show: isSuccess }]"
          :style="`transform: translateX(${
            isSuccess ? `${canvasWidth + canvasHeight * 0.578}px` : `-${canvasHeight * 0.578}px`
          }) skew(-30deg, 0);`"
        />
        <img class="reset_" :src="resetSvg" @click="reset" />
      </div>
      <div v-if="false" class="auth-control_">
        <div class="range-box" :style="`height:${sliderBaseSize}px`">
          <div class="range-text">{{ sliderText }}</div>
          <div ref="rangeSlider" class="range-slider" :style="`width:${styleWidth}px`">
            <div
              :class="['range-btn', { isDown: mouseDown }]"
              :style="`width:${sliderBaseSize}px`"
              @mousedown="onRangeMouseDown($event)"
              @touchstart="onRangeMouseDown($event)"
            >
              <div />
              <div />
              <div />
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div v-if="true" class="auth-control_" @mouseover="handleOver" @mouseout="handleOut">
    <div class="range-box" :style="`height:${sliderBaseSize}px`">
      <div class="range-text">{{ sliderText }}</div>
      <div ref="rangeSlider" class="range-slider" :style="`width:${styleWidth}px`">
        <div
          :class="['range-btn', { isDown: mouseDown }]"
          :style="`width:${sliderBaseSize}px`"
          @mousedown="onRangeMouseDown($event)"
          @touchstart="onRangeMouseDown($event)"
        >
          <div />
          <div />
          <div />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  // import { captcha, captchaVerify } from '@/api/common/common';
  import {
    onMounted,
    toRefs,
    defineComponent,
    reactive,
    onBeforeMount,
    watch,
    computed,
    ref,
  } from 'vue';
  import resetSvg from '@/views/login/components/PuzzleCode/reset.png';
  export default defineComponent({
    name: 'PuzzleCode',
    /** 父级参数 **/
    props: {
      id: { type: String, default: undefined },
      canvasWidth: { type: Number, default: 320 }, // 主canvas的宽
      canvasHeight: { type: Number, default: 180 }, // 主canvas的高
      // 是否出现，由父级控制
      show: { type: Boolean, default: false },
      sliderSize: { type: Number, default: 35 }, // 滑块的大小
      successText: {
        type: String,
        default: '验证通过！',
      },
      failText: {
        type: String,
        default: '验证失败，请重试',
      },
      sliderText: {
        type: String,
        default: '拖动滑块完成拼图',
      },
      borderRadius: {
        type: Number,
        default: 0,
      },
    },
    emits: ['close', 'fail', 'success'],
    setup(props, { emit }) {
      const state = reactive({
        image1: undefined, // 大图
        image2: undefined, // 小图
        mouseDown: false, // 鼠标是否在按钮上按下
        startWidth: 50, // 鼠标点下去时父级的width
        startX: 0, // 鼠标按下时的X
        newX: 0, // 鼠标当前的偏移X
        loading: true, // 是否正在加载中，主要是等图片onload
        isCanSlide: false, // 是否可以拉动滑动条
        error: false, // 图片加在失败会出现这个，提示用户手动刷新
        infoBoxShow: false, // 提示信息是否出现
        infoText: '', // 提示等信息
        infoBoxFail: false, // 是否验证失败
        timer1: null, // setTimout1
        closeDown: false, // 为了解决Mac上的click BUG
        isSuccess: false, // 验证成功
        resetSvg,
        isSubmit: false, // 是否正在验证中
        rangeSlider: ref(),
        isSlider: false,
      });
      /** 监听 **/
      watch(
        () => props.show,
        (newV) => {
          // 每次出现都应该重新初始化
          if (newV) {
            document.body.classList.add('vue-puzzle-overflow');
            methods.reset();
          } else {
            document.body.classList.remove('vue-puzzle-overflow');
          }
        },
        { deep: true },
      );
      /** 计算属性 **/
      // styleWidth是底部用户操作的滑块的父级，就是轨道在鼠标的作用下应该具有的宽度
      const styleWidth = computed(() => {
        const w = state.startWidth + state.newX - state.startX;
        return w < sliderBaseSize.value
          ? sliderBaseSize
          : w > props.canvasWidth
          ? props.canvasWidth
          : w;
      });
      // 处理一下sliderSize，弄成整数，以免计算有偏差
      const sliderBaseSize = computed(() => {
        return Math.max(
          Math.min(Math.round(props.sliderSize), Math.round(props.canvasWidth * 0.5)),
          10,
        );
      });
      /** 方法 **/
      const methods = {
        // 关闭
        onClose() {
          if (!state.mouseDown) {
            clearTimeout(state.timer1);
            emit('close');
          }
        },
        onCloseMouseDown() {
          // state.closeDown = true;
        },
        onCloseMouseUp() {
          if (state.closeDown) {
            methods.onClose();
          }
          state.closeDown = false;
        },
        // 鼠标按下准备拖动
        onRangeMouseDown(e) {
          if (state.isCanSlide) {
            state.mouseDown = true;
            state.startWidth = state.rangeSlider.clientWidth;
            state.newX = e.clientX || e.changedTouches[0].clientX;
            state.startX = e.clientX || e.changedTouches[0].clientX;
          }
        },
        // 鼠标移动
        onRangeMouseMove(e) {
          if (state.mouseDown) {
            e.preventDefault();
            state.newX = e.clientX || e.changedTouches[0].clientX;
          }
        },
        // 鼠标抬起
        onRangeMouseUp() {
          if (state.mouseDown) {
            state.mouseDown = false;
            methods.submit();
          }
        },
        /**
         * 开始进行
         */
        init() {
          state.loading = true;
          state.isCanSlide = false;
          // captcha().then((res) => {
          //   state.image1 = res.image1;
          //   state.image2 = res.image2;
          //   state.loading = false;
          //   state.isCanSlide = true;
          //   // this.startTime = new Date().getTime();
          // });
        },
        // 开始判定
        submit() {
          // 关闭拖动
          state.isCanSlide = false;
          state.isSubmit = true;
          const x = state.newX - state.startX;
          state.loading = true;
          // captchaVerify({ x, width: this.canvasWidth }).then((res) => {
          //   state.isSubmit = false;
          //   state.loading = false;
          //   if (res.success) {
          //     // 成功
          //     state.infoText = props.successText;
          //     state.infoBoxFail = false;
          //     state.infoBoxShow = true;
          //     state.isCanSlide = false;
          //     state.isSuccess = true;
          //     // 成功后准备关闭
          //     clearTimeout(state.timer1);
          //     state.timer1 = setTimeout(() => {
          //       // 成功的回调
          //       emit('success', x);
          //     }, 800);
          //   } else {
          //     // 失败
          //     state.infoText = props.failText;
          //     state.infoBoxFail = true;
          //     state.infoBoxShow = true;
          //     state.isCanSlide = false;
          //     // 失败的回调
          //     emit('fail', x);
          //     // 800ms后重置
          //     clearTimeout(state.timer1);
          //     state.timer1 = setTimeout(() => {
          //       methods.reset();
          //     }, 800);
          //   }
          // });
        },
        // 重置
        reset() {
          state.infoBoxFail = false;
          state.infoBoxShow = false;
          state.isCanSlide = true;
          state.isSuccess = false;
          state.startWidth = sliderBaseSize; // 鼠标点下去时父级的width
          state.startX = 0; // 鼠标按下时的X
          state.newX = 0; // 鼠标当前的偏移X
          methods.init();
        },
        handleOver() {
          console.log();
          state.isSlider = true;
        },
        handleOut() {
          state.isSlider = false;
        },
      };
      onBeforeMount(() => {
        clearTimeout(state.timer1);
        // document.body.removeChild(this.$el);
        document.removeEventListener('mousemove', methods.onRangeMouseMove, false);
        document.removeEventListener('mouseup', methods.onRangeMouseUp, false);

        document.removeEventListener('touchmove', methods.onRangeMouseMove, {
          passive: false,
        });
        document.removeEventListener('touchend', methods.onRangeMouseUp, false);
      });
      /** 生命周期 **/
      onMounted(() => {
        // document.body.appendChild(this.$el);
        document.addEventListener('mousemove', methods.onRangeMouseMove, false);
        document.addEventListener('mouseup', methods.onRangeMouseUp, false);

        document.addEventListener('touchmove', methods.onRangeMouseMove, {
          passive: false,
        });
        document.addEventListener('touchend', methods.onRangeMouseUp, false);
        if (props.show) {
          document.body.classList.add('vue-puzzle-overflow');
          methods.reset();
        }
      });
      return {
        ...toRefs(state),
        styleWidth,
        sliderBaseSize,
        ...methods,
      };
    },
  });
</script>
<style lang="less">
  .vue-puzzle-vcode {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    // z-index: 50;
    // background-color: rgba(0, 0, 0, 0.3);
    // z-index: 999;
    // opacity: 0;
    // pointer-events: none;
    // transition: opacity 200ms;
    // &.show_ {
    //   opacity: 1;
    //   pointer-events: auto;
    // }
  }
  .vue-auth-box_ {
    position: absolute;
    top: 40%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 20px;
    background: #fff;
    user-select: none;
    border-radius: 3px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    .auth-body_ {
      position: relative;
      overflow: hidden;
      border-radius: 3px;
      .loading-box_ {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.8);
        z-index: 20;
        opacity: 1;
        transition: opacity 200ms;
        display: flex;
        align-items: center;
        justify-content: center;
        &.hide_ {
          opacity: 0;
          pointer-events: none;
          .loading-gif_ {
            span {
              animation-play-state: paused;
            }
          }
        }
        .loading-gif_ {
          flex: none;
          height: 5px;
          line-height: 0;
          @keyframes load {
            0% {
              opacity: 1;
              transform: scale(1.3);
            }
            100% {
              opacity: 0.2;
              transform: scale(0.3);
            }
          }
          span {
            display: inline-block;
            width: 5px;
            height: 100%;
            margin-left: 2px;
            border-radius: 50%;
            background-color: #888;
            animation: load 1.04s ease infinite;
            &:nth-child(1) {
              margin-left: 0;
            }
            &:nth-child(2) {
              animation-delay: 0.13s;
            }
            &:nth-child(3) {
              animation-delay: 0.26s;
            }
            &:nth-child(4) {
              animation-delay: 0.39s;
            }
            &:nth-child(5) {
              animation-delay: 0.52s;
            }
          }
        }
      }
      .info-box_ {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        height: 24px;
        line-height: 24px;
        text-align: center;
        overflow: hidden;
        font-size: 13px;
        background-color: #83ce3f;
        opacity: 0;
        transform: translateY(24px);
        transition: all 200ms;
        color: #fff;
        z-index: 10;
        &.show {
          opacity: 0.95;
          transform: translateY(0);
        }
        &.fail {
          background-color: #ce594b;
        }
      }
      .auth-canvas2_ {
        position: absolute;
        top: 0;
        left: 0;
        z-index: 2;
      }
      .auth-canvas3_ {
        position: absolute;
        top: 0;
        left: 0;
        opacity: 0;
        transition: opacity 600ms;
        z-index: 3;
        &.show {
          opacity: 1;
        }
      }
      .flash_ {
        position: absolute;
        top: 0;
        left: 0;
        width: 30px;
        height: 100%;
        background-color: rgba(255, 255, 255, 0.1);
        z-index: 3;
        &.show {
          transition: transform 600ms;
        }
      }
      .reset_ {
        position: absolute;
        top: 2px;
        right: 2px;
        width: 35px;
        height: auto;
        z-index: 12;
        cursor: pointer;
        transition: transform 200ms;
        transform: rotate(0deg);
        &:hover {
          transform: rotate(-90deg);
        }
      }
    }
    .auth-control_ {
      .range-box {
        position: relative;
        width: 100%;
        background-color: #eef1f8;
        margin-top: 20px;
        border-radius: 3px;
        box-shadow: 0 0 8px rgba(240, 240, 240, 0.6) inset;
        .range-text {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          font-size: 14px;
          color: #b7bcd1;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          text-align: center;
          width: 100%;
        }
        .range-slider {
          position: absolute;
          height: 100%;
          width: 50px;
          background-color: rgba(106, 160, 255, 0.8);
          border-radius: 3px;
          .range-btn {
            position: absolute;
            display: flex;
            align-items: center;
            justify-content: center;
            right: 0;
            width: 50px;
            height: 100%;
            background-color: #fff;
            border-radius: 3px;
            box-shadow: 0 0 4px #ccc;
            cursor: pointer;
            & > div {
              width: 0;
              height: 40%;

              transition: all 200ms;
              &:nth-child(2) {
                margin: 0 4px;
              }
              border: solid 1px #6aa0ff;
            }
            &:hover,
            &.isDown {
              & > div:first-child {
                border: solid 4px transparent;
                height: 0;
                border-right-color: #6aa0ff;
              }
              & > div:nth-child(2) {
                border-width: 3px;
                height: 0;
                border-radius: 3px;
                margin: 0 6px;
                border-right-color: #6aa0ff;
              }
              & > div:nth-child(3) {
                border: solid 4px transparent;
                height: 0;
                border-left-color: #6aa0ff;
              }
            }
          }
        }
      }
    }
  }
  .vue-puzzle-overflow {
    overflow: hidden !important;
  }
  .auth-control_ {
    .range-box {
      position: relative;
      width: 100%;
      background-color: #eef1f8;
      margin-top: 20px;
      border-radius: 3px;
      box-shadow: 0 0 8px rgba(240, 240, 240, 0.6) inset;
      .range-text {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-size: 14px;
        color: #b7bcd1;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        text-align: center;
        width: 100%;
      }
      .range-slider {
        position: absolute;
        height: 100%;
        width: 50px;
        background-color: rgba(106, 160, 255, 0.8);
        border-radius: 3px;
        .range-btn {
          position: absolute;
          display: flex;
          align-items: center;
          justify-content: center;
          right: 0;
          width: 50px;
          height: 100%;
          background-color: #fff;
          border-radius: 3px;
          box-shadow: 0 0 4px #ccc;
          cursor: pointer;
          & > div {
            width: 0;
            height: 40%;

            transition: all 200ms;
            &:nth-child(2) {
              margin: 0 4px;
            }
            border: solid 1px #6aa0ff;
          }
          &:hover,
          &.isDown {
            & > div:first-child {
              border: solid 4px transparent;
              height: 0;
              border-right-color: #6aa0ff;
            }
            & > div:nth-child(2) {
              border-width: 3px;
              height: 0;
              border-radius: 3px;
              margin: 0 6px;
              border-right-color: #6aa0ff;
            }
            & > div:nth-child(3) {
              border: solid 4px transparent;
              height: 0;
              border-left-color: #6aa0ff;
            }
          }
        }
      }
    }
  }
</style>
